/*
 * The JAnalytics Library provides a Java API to the Google Analytics service.
 * Copyright (C) 2007 Ansir Development Limited (http://www.ansir.ca)
 * 
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 * 
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

package ca.ansir.analytics.transform;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.Writer;

import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import ca.ansir.analytics.util.Utilities;

/**
 * The <code>TemplateTransform</code> is used to apply an XSL Transformation
 * (XSLT) to transform an XML <code>InputStream</code> into another document.
 * 
 * @author Dan Andrews
 */
public class TemplateTransform {

	// private static boolean cauchoExists = false;
	//
	// static {
	// try {
	// Class.forName("com.caucho.xml.XmlParseException");
	// cauchoExists = true;
	// } catch (ClassNotFoundException e) {
	// cauchoExists = false;
	// }
	// }

	/**
	 * Apply the transform described by the XSL <code>InputStream</code> to
	 * the XML <code>InputStream</code> and write the results to the given
	 * writer. Both the XML and XSL <code>InputStream</code> objects are
	 * guaranteed to be closed, however, the closing of the writer is left to
	 * the client code.
	 * 
	 * @param inXML
	 *            The XML <code>InputStream</code> object.
	 * @param inXSL
	 *            The XSL <code>InputStream</code> object.
	 * @param writer
	 *            The <code>Writer</code> object.
	 * @throws TransformerException
	 */
	public static void applyTransform(InputStream inXML, InputStream inXSL,
			Writer writer) throws TransformerException {
		applyTransform(inXML, inXSL, writer, null);
	}

	/**
	 * Apply the transform described by the XSL <code>InputStream</code> to
	 * the XML <code>InputStream</code> and write the results to the given
	 * writer. Both the XML and XSL <code>InputStream</code> objects are
	 * guaranteed to be closed, however, the closing of the writer is left to
	 * the client code.
	 * 
	 * @param inXML
	 *            The XML <code>InputStream</code> object.
	 * @param inXSL
	 *            The XSL <code>InputStream</code> object.
	 * @param writer
	 *            The <code>Writer</code> object.
	 * @param resolver
	 *            Optional for future use.
	 * @throws TransformerException
	 */
	public static void applyTransform(InputStream inXML, InputStream inXSL,
			Writer writer, URIResolver resolver) throws TransformerException {
		try {
			TransformerFactory tf = TransformerFactory.newInstance();
			Templates template = tf.newTemplates(new StreamSource(inXSL));
			Transformer tfm = template.newTransformer();
			if (resolver != null) {
				tfm.setURIResolver(resolver);
			}
			Utilities.configureTransformerIndent(tf, tfm);

			Source source = new StreamSource(inXML);
			Result result = new StreamResult(writer);

			tfm.transform(source, result);
		} finally {
			close(inXML, inXSL, writer);
		}
	}

//	/**
//	 * Apply the transform using JDOM.
//	 * 
//	 * @param inXML
//	 *            The XML <code>InputStream</code> object.
//	 * @param inXSL
//	 *            The XSL <code>InputStream</code> object.
//	 * @param writer
//	 *            The <code>Writer</code> object.
//	 * @throws TransformerException
//	 */
//	public static void applyJDomTransform(InputStream inXML, InputStream inXSL,
//			Writer writer) throws TransformerException {
//		applyJDomTransform(inXML, inXSL, writer, null);
//	}
//	/**
//	 * Apply the transform using JDOM.
//	 * 
//	 * @param inXML
//	 *            The XML <code>InputStream</code> object.
//	 * @param inXSL
//	 *            The XSL <code>InputStream</code> object.
//	 * @param writer
//	 *            The <code>Writer</code> object.
//	 * @param resolver
//	 *            Optional for future use.
//	 * @throws TransformerException
//	 */
//	public static void applyJDomTransform(InputStream inXML, InputStream inXSL,
//			Writer writer, URIResolver resolver) throws TransformerException {
//		try {
//			SAXBuilder saxBuilder = new SAXBuilder();
//			XSLTransformer transformer = new XSLTransformer(inXSL);
//			Document document = saxBuilder.build(inXML);
//			Document transformed = transformer.transform(document);
//			serializeAsUTF8(transformed, writer);
//		} catch (JDOMException e) {
//			throw new TransformerException(e.getMessage(), e);
//		} catch (IOException e) {
//			throw new TransformerException(e.getMessage(), e);
//		} finally {
//			close(inXML, inXSL, writer);
//		}
//
//	}
//
//	public static void serializeAsUTF8(org.jdom.Document document, Writer writer)
//			throws IOException {
//		Format f = Format.getPrettyFormat();
//		f.setEncoding("UTF-8");
//		XMLOutputter serializer = new XMLOutputter(f);
//		serializer.output(document, writer);
//	}

	private static void close(InputStream inXML, InputStream inXSL,
			Writer writer) throws TransformerException {
		if (writer != null) {
			// leave to clients to close
		}
		if (inXML != null) {
			try {
				inXML.close();
			} catch (IOException e) {
				throw new TransformerException(
						"Could not close XML InputStream.", e);
			}
		}
		if (inXSL != null) {
			try {
				inXSL.close();
			} catch (IOException e) {
				throw new TransformerException(
						"Could not close XSL InputStream.", e);
			}
		}
	}

	// private static TransformerFactory getTransformerFactory() {
	//		
	// javax.xml.transform.TransformerFactory.
	// // workaround for com.caucho.xml.XmlParseException
	// boolean isJDK14 = System.getProperty("java.version").startsWith("1.4");
	// boolean isJDK15 = System.getProperty("java.version").startsWith("1.5");
	// boolean isJDK16 = System.getProperty("java.version").startsWith("1.6");
	// TransformerFactory tf = null;
	// Class transformerFactoryClass = null;
	// if (isJDK15 || isJDK16) {
	// String className =
	// "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";
	// try {
	// transformerFactoryClass = Class.forName(className);
	// } catch (ClassNotFoundException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// } else if (isJDK14) {
	// String className = "org.apache.xalan.processor.TransformerFactoryImpl";
	// try {
	// transformerFactoryClass = Class.forName(className);
	// } catch (ClassNotFoundException e) {
	// // TODO Auto-generated catch block
	// e.printStackTrace();
	// }
	// }
	// {
	//			
	//			
	//			
	// }
	// if (transformerFactoryClass != null) {
	// try {
	// tf = (TransformerFactory) transformerFactoryClass.newInstance();
	// } catch (InstantiationException e) {
	// } catch (IllegalAccessException e) {
	// }
	// }
	// if (tf == null) {
	// tf = TransformerFactory.newInstance();
	// }
	// return tf;
	// }

	/**
	 * Used for quick testing of the xsl.
	 * 
	 * @param args
	 *            Not used.
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		FileInputStream in = new FileInputStream("C:/geomapoverlay.xml");

		FileInputStream inXsl = new FileInputStream("C:/kml.xsl");
		Writer w = new PrintWriter(System.out);
		applyTransform(in, inXsl, w);
	}

}
